package com.rw.tool.util.string;

import java.math.BigDecimal;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 字符串扫描类
 */
public class StringScanner {
    // 输入的字符串
    private final String input;

    // 当前字符串扫描到的位置
    private int index = 0;

    // 数字类型的字符串正则表达式
    private static final Pattern FLOAT_PATTERN = Pattern.compile("^-?\\d+(\\.\\d+)?");

    // 布尔类型的字符串正则表达式
    private static final Pattern BOOL_PATTERN = Pattern.compile("^(true|false)", Pattern.CASE_INSENSITIVE);

    public StringScanner(String input) {
        if (input == null) {
            throw new StringScannerException("Input string is null!");
        }
        this.input = input;
    }

    /**
     * 获取当前字符串扫描的位置
     */
    public int getIndex() {
        return index;
    }

    /**
     * 设置当前字符串扫描的位置
     */
    public void setIndex(int index) {
        if (index < 0 || index >= input.length()) {
            String errorMessage = "Index out of bounds! The index should be between 0 and {}";
            throw new IndexOutOfBoundsException(StringFormatter.format(errorMessage, input.length()));
        }
        this.index = index;
    }

    /**
     * 字符串是否有剩余某一段未扫描
     */
    public boolean hasNext() {
        return index < input.length();
    }

    /**
     * 字符串接下来是否拥有匹配正则表达式的一段
     */
    public boolean hasNext(String regex) {
        Pattern pattern = Pattern.compile(addPrefix(regex));
        return hasNext(pattern);
    }

    /**
     * 字符串接下来是否有一段数字
     */
    public boolean hasNextNumber() {
        return hasNext(FLOAT_PATTERN);
    }

    /**
     * 字符串接下来是否有一段布尔值
     */
    public boolean hasNextBoolean() {
        return hasNext(BOOL_PATTERN);
    }

    /**
     * 取出字符串接下来的所有字符
     */
    public String nextAll() {
        String next = input.substring(index);
        index = input.length();
        return next;
    }

    /**
     * 取出接下来匹配正则表达式的字符
     */
    public String next(String regex) {
        return next(Pattern.compile(addPrefix(regex)));
    }

    /**
     * 取出接下来匹配的数字
     */
    public BigDecimal nextNumber() {
        return new BigDecimal(next(FLOAT_PATTERN));
    }

    /**
     * 取出接下来匹配的布尔值
     */
    public boolean nextBoolean() {
        return Boolean.parseBoolean(next(BOOL_PATTERN));
    }

    private String addPrefix(String regex) {
        if (StringUtil.startsWith(regex, "^")) {
            return regex;
        }
        return "^" + regex;
    }

    private boolean hasNext(Pattern pattern) {
        Matcher matcher = pattern.matcher(input.substring(index));
        return matcher.find();
    }

    private String next(Pattern pattern) {
        Matcher matcher = pattern.matcher(input.substring(index));
        if (!matcher.find()) {
            throw new StringScannerException("Illegal string match!");
        }
        String result = matcher.group();
        index += result.length();
        return result;
    }
}
